// Copyright 2010 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.


/**
 * @fileoverview Provides data and functionality for status related
 * information.  All objects under the shell extension use status properties to
 * represent their state, i.e. whether they are able to be used and their load
 * state.  Different objects may use different pieces of information.
 *
 * Public functions/enums:
 *   shellExtension.status.Value - An enumeration of valid status values.
 *   shellExtension.status.determine - Given an array of objects containing a
 *       getStatus function that returns a shellExtension.status.Value,
 *       determine the status of the group based on a prioritized set of status
 *       values.
 *   shellExtension.status.isValid - Checks if the given string is a valid
 *       status value.
 *
 * @author jasonstredwick@google.com (Jason Stredwick)
 */


goog.provide('shellExtension.status');

goog.require('shellExtension.utils');


/**
 * An enumeration of status values for the different shell extension objects.
 * @enum {string}
 */
shellExtension.status.Value = {
  BAD_OBJECT: 'bad-object',
  FAILED: 'failed',
  INIT: 'init',
  LOADED: 'loaded',
  LOADING: 'loading',
  READY: 'ready',
  WARNING: 'warning'
};


/**
 * Loops over the array of objects examining their status.  It returns a status
 * representing the group as whole where the status value is prioritized.  The
 * priority from high to low is
 *
 *     FAILED
 *     INIT
 *     LOADED
 *
 * An example is as follows, if the status values are
 *
 *     [loaded, init, loaded, failed]
 *
 * then the result will be failed.  The function assumes that each object has a
 * getStatus member function that returns a shellExtension.Status value.
 * @param {!Array.<!Object>} data An array of objects that have a getStatus
 *     function that returns a shellExtension.status.Value.
 * @return {shellExtension.status.Value} The prioritized status.
 *     FAILED || INIT || LOADED.
 */
shellExtension.status.determine = function(data) {
  var init = false;

  // Try/catch is in case the inputs are not as expected and the array does not
  // contain objects with a getStatus function.
  try {
    for (var i = 0, len = data.length; i < len; ++i) {
      switch (data[i].getStatus()) {
        case shellExtension.status.Value.INIT:
          init = true;
          break;
        case shellExtension.status.Value.LOADED:
          break;
        // BAD_OBJECT || FAILED || LOADING || UNKNOWN == FAILED
        case shellExtension.status.Value.BAD_OBJECT:
        case shellExtension.status.Value.FAILED:
        case shellExtension.status.Value.LOADING:
        default:
          return shellExtension.status.Value.FAILED;
      }
    }
  } catch (error) {
    return shellExtension.status.Value.FAILED;
  }

  // If there is at least one INIT and no failures then the status is INIT.
  if (init) {
    return shellExtension.status.Value.INIT;
  }

  return shellExtension.status.Value.LOADED;
};


/**
 * Given layer and its data status values, determine the resulting overall
 * layer status.  The results are calculated such that
 *     LOADED = layer LOADED and data LOADED
 *     INIT = layer LOADED and data INIT or layer INIT and data INIT
 *     WARNING = layer LOADED or layer INIT
 *     FAILED = layer !LOADED and layer !INIT
 * Expected inputs are a subset of all values [LOADED, INIT, FAILED], and
 * potentially BAD_OBJECT.
 * @param {shellExtension.status.Value} layerStatus The layer's status.
 * @param {shellExtension.status.Value} dataStatus The layer's data status.
 * @return {shellExtension.statusValue} The resulting status.
 */
shellExtension.status.determineLayer = function(layerStatus, dataStatus) {
  // Only consider the layer loaded if it and its scripts are both loaded.
  if (status == statusEnum.LOADED && dataStatus == statusEnum.LOADED) {
    return shellExtension.status.Value.LOADED;
  // Consider the layer unloaded if its data is in the init state and the
  // layer has at least been initialized.
  } else if (status == statusEnum.INIT && dataStatus == statusEnum.INIT ||
             status == statusEnum.LOADED && dataStatus == statusEnum.INIT) {
    return shellExtension.status.Value.INIT;
  // If the layer has at least been initialized then any non-init/not-loaded
  // data state marks the layer in a warning state.
  } else if (status == statusEnum.INIT || status == statusEnum.LOADED) {
    return shellExtension.status.Value.WARNING;
  }
  return shellExtension.status.Value.FAILED;
};


/**
 * Checks if the given status string value is a valid shellExtension.Status
 * value.
 * @param {string} value The value to check.
 * @return {boolean} Whether or not it is a valid status value.
 */
shellExtension.status.isValid = function(value) {
  return shellExtension.utils.inEnum(value, shellExtension.status.Value);
};

